
package com.zhenai.lancering.ui;

import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.zhenai.lancering.R;
import com.zhenai.lancering.controller.AudioCapture;
import com.zhenai.lancering.controller.AudioDetector;
import com.zhenai.lancering.model.AudioConfiguration;
import com.zhenai.lancering.model.DetectorConfiguration;
import com.zhenai.lancering.model.service.TvShowService;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;


public class SpringFestivalGalaActivity extends Activity {
    private static final String TAG = "sync.SpringFestival";
    private static final int REQUEST_START_DETECTION_PERMISSIONS = 123;
    private static int sNbDetectorToRun;
    private Vector<AudioDetector> mDetectors;
    private Vector<DetectorConfiguration> mDetectorConfigs;
    private AudioCapture mAudioCapture;

    private RelativeLayout rlRoot;
    private ImageView ivWave;
    private TextView tvTip;
    private Button btnRegAgain;
    private TextView tvDesc;
    private boolean hasDetected = false;
    private TvShowService mService;

    static {
        java.lang.System.loadLibrary("soxr");
        java.lang.System.loadLibrary("SyncNowJNI");
    }

    public static void start(Context context) {
        context.startActivity(new Intent(context, SpringFestivalGalaActivity.class));
    }

    public int getLayoutId() {
        return R.layout.aty_spring_festival_gala;
    }

    public void init() {
//        mService = ZANetwork.getService(TvShowService.class);
        ///for ink only
        sNbDetectorToRun = 1;
        mDetectors = new Vector<>(sNbDetectorToRun, 1);
        mDetectorConfigs = new Vector<>(sNbDetectorToRun, 1);
        for (int i = 0; i < sNbDetectorToRun; i++) {
            mDetectorConfigs.add(new DetectorConfiguration());
        }
    }

    public void findViews() {
        rlRoot = (RelativeLayout) findViewById(R.id.rlRoot);
        tvTip = (TextView) findViewById(R.id.tvTip);
        ivWave = (ImageView) findViewById(R.id.ivWave);
        btnRegAgain = (Button) findViewById(R.id.btnRegAgain);
        tvDesc = (TextView) findViewById(R.id.tvDesc);
    }

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        init();
        super.onCreate(savedInstanceState);
        setContentView(getLayoutId());
        findViews();
        bindListener();
    }

    //    @Override
//    public void initViewData() {
//        setTitle("电视互动");
//        getPowerDesc();
//    }

    public void bindListener() {
        rlRoot.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (null == mAudioCapture) {
                    if (checkPermissions(REQUEST_START_DETECTION_PERMISSIONS)) {
                        startDetection();
                        rlRoot.setEnabled(false);
//                        ZAImageLoader.get().with(SpringFestivalGalaActivity.this)
//                                .load(R.drawable.ani_sync_now_wave)
//                                .crop(ImageLoaderOptions.CROP_TYPE_CENTER).into(ivWave);
                        ivWave.setImageResource(R.drawable.ani_sync_now_wave);
                        hasDetected = false;
                    } else {
                        Toast.makeText(getApplicationContext(), "请授予采集音频的权限。", Toast.LENGTH_LONG).show();
                    }
                } else {
                    stopDetection();
                    Toast.makeText(getApplicationContext(), "音频采集失败，请退出页面重试！", Toast.LENGTH_LONG).show();
                    setTip("未识别到活动内容", R.color.color_ff7d7d7d);
                    btnRegAgain.setVisibility(View.VISIBLE);
                    ivWave.setImageResource(R.drawable.ic_sync_now_fail);
                }
            }
        });
        btnRegAgain.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (null == mAudioCapture) {
                    if (checkPermissions(REQUEST_START_DETECTION_PERMISSIONS)) {
                        startDetection();
                        btnRegAgain.setVisibility(View.INVISIBLE);
                        ivWave.setImageResource(R.drawable.ani_sync_now_wave);
                        hasDetected = false;
                    } else {
                        Toast.makeText(getApplicationContext(), "请授予采集音频的权限。", Toast.LENGTH_LONG).show();
                    }
                } else {
                    stopDetection();
                    Toast.makeText(getApplicationContext(), "音频采集失败，请退出页面重试！", Toast.LENGTH_LONG).show();
                    setTip("未识别到活动内容", R.color.color_ff7d7d7d);
                    btnRegAgain.setVisibility(View.VISIBLE);
                    ivWave.setImageResource(R.drawable.ic_sync_now_fail);
                }
            }
        });

    }

//    private void getPowerDesc() {
//        ZANetwork.with(this)
//                .api(mService.getPowerDesc())
//                .callback(new ZANetworkCallback<ZAResponse<PowerDescEntity>>() {
//
//                    @Override
//                    public void onBusinessSuccess(ZAResponse<PowerDescEntity> response) {
//                        if (response != null && response.data != null) {
//                            tvDesc.setText(response.data.msg);
//                        }
//                    }
//
//                    @Override
//                    public void onError(Throwable e) {
//                    }
//
//                });
//    }
//
//    private void getVoiceAtyPage(String contentID) {
//        ZANetwork.with(this)
//                .api(mService.getVoiceAtyPage(contentID))
//                .callback(new ZANetworkCallback<ZAResponse<VoiceShowEntity>>() {
//                    @Override
//                    public void onBusinessSuccess(ZAResponse<VoiceShowEntity> response) {
//                        if (response != null && response.data != null) {
//                            String url = response.data.url;
//                            if (TextUtils.isEmpty(url)) {
//                                Toast.makeText(getApplicationContext(), "找不到对应的页面", Toast.LENGTH_LONG).show();
//                            } else {
//                                ZARouter.build()
//                                        .type(RouterCode.TYPE_H5)
//                                        .url(url)
//                                        .title("电视互动")
//                                        .router(getContext());
//                                Toast.makeText(getApplicationContext(), "识别到内容，即将跳转", Toast.LENGTH_LONG).show();
//                            }
//                        }
//                    }
//
//                    @Override
//                    public void onError(Throwable e) {
//                        Toast.makeText(getApplicationContext(), "找不到对应的页面", Toast.LENGTH_LONG).show();
//                    }
//                });
//    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        stopDetection();
        if (mCountDownTimer != null) {
            mCountDownTimer.cancel();
        }
    }

    private boolean updateSettings() {
        boolean retCode = true;
        try {
            for (int i = 0; i < sNbDetectorToRun; i++) {
                mDetectorConfigs.elementAt(i).logEnabled = false;
                mDetectorConfigs.elementAt(i).numIdentifierBits = 4;
                mDetectorConfigs.elementAt(i).numTimeStampBits = 8;
                mDetectorConfigs.elementAt(i).license =
                        "kAAwHIyN04r6qdmsZzI1wQYFHXV9/w80ML2Uf7MUtBZuSNMhFAV8Y7WYpk8nWnG26esOTY0id/O0droHFakQQ8bj/CIoSe+2P4oIwd43epay2b4WWR72f6yK9mtQaKLFpWFAFYKlFHYpIrzr7wwAXhm3zDfKRXPiBTc2sb9mtl5F42ZP1EYDbIKaT5IZ6U98GrtBAE1DMENGQ0ZDSlAxU0FaRkJHOUZWQ2E4M0p6V0JtTC80QWhVQTE1dDdnSXg3RnhLZW9zY2RCVDJJUU5iQnErTT0A";

                mDetectorConfigs.elementAt(i).numIdentifierBits = 32;
                mDetectorConfigs.elementAt(i).numTimeStampBits = 0;
            }
        } catch (Exception ex) {
            verboseLog(ex.getMessage());
            retCode = false;
        }
        return retCode;
    }

    private synchronized boolean startDetectors(boolean isRecordEnabled) {
        // Update detection parameters from preferences before configuring the SDK
        if (!updateSettings()) {
            showErrorTip(5);
            return false;
        }
        // Create and initialize the AudioCapture
        try {
            mAudioCapture = new AudioCapture(this) {
                @Override
                public void onError(int code, String msg) {
                    super.onError(code, msg);
                    stopDetection();
                    showErrorTip(1);
                }
            };
        } catch (Exception e) {
            verboseLog(e.getMessage());
            showErrorTip(2);
            return false;
        }

        AudioConfiguration audioConfig = mAudioCapture.getAudioConfiguration();
        int isError = 0;
        for (int i = 0; i < sNbDetectorToRun; i++) {
            try {
                mDetectorConfigs.elementAt(i).recordEnabled = isRecordEnabled;
                mDetectorConfigs.elementAt(i).instName = "Inst" + i;
                mDetectors.add(new AudioDetector(this, audioConfig, mDetectorConfigs.elementAt(i)) {
                    @Override
                    public void onDebug(String text) {
                        Log.e(TAG, "[onDebug] text:" + text);
                    }

                    @Override
                    public void onPayload(final PayloadEvent event) {
                        Log.e(TAG, "[onPayload] awmTechnology:" + event.awmTechnology + ",confidence:" + event.confidence
                                + ",contentID.value:" + event.contentID.value + ",contentID.lsb:" + event.contentID.lsb + ""
                                + ",contentID.msb:" + event.contentID.msb + "" + ",offset:" + event.offset + ",payloadType:" + event.payloadType
                                + ",referenceTime:" + event.referenceTime + ",timeCodeNtamLsb:" + event.timeCodeNtamLsb
                                + ",timeStamp:" + event.timeStamp + ",timeCodeNtamMsb:" + event.timeCodeNtamMsb);
                        if (PayloadType.TYPE_IDENTIFIED == event.payloadType) {  //成功识别到内容
                            if (!hasDetected && rlRoot != null) {
                                rlRoot.post(new Runnable() {
                                    @Override
                                    public void run() {
                                        hasDetected = true;
                                        if (event != null && event.contentID != null) {
//                                            getVoiceAtyPage(event.contentID + "");
                                        }
                                        stopDetection();
                                        if (mCountDownTimer != null) {
                                            mCountDownTimer.cancel();
                                            setTip("点击屏幕开始识别", R.color.color_ff8a53f7);
                                            ivWave.setImageResource(R.drawable.ic_sync_start);
                                            rlRoot.setEnabled(true);
                                        }
                                    }
                                });
                            }
                        } else if (PayloadType.TYPE_MARKED_BUT_NOT_IDENTIFIED == event.payloadType) { //内容匹配，但是识别不出来

                        } else {      //内容识别失败

                        }
                    }

                    @Override
                    public void onAlarm(AlarmEvent event) {
                        Log.e(TAG, "[onAlarm] text:" + event.message);
                    }

                    @Override
                    public void onError(int code, String msg) {

                    }
                });
            } catch (Exception e) {
                verboseLog(e.getMessage());
                showErrorTip(3);
                isError++;
            }
        }

        //Don't start detection if a bad license
        if (isError > 0) {
            stopDetection();
            return false;
        }
        mAudioCapture.setPriority(Thread.MAX_PRIORITY);
        mAudioCapture.start();
        return true;
    }

    private void showErrorTip(int from) {
        Toast.makeText(this, "音频采集失败，请退出页面重试！错误码：" + from, Toast.LENGTH_LONG).show();
    }

    /**
     * Wrapper around startDetector() managing the UI buttons enabling.
     **/
    private synchronized void startDetection() {
        synchronized (this) {
            if (startDetectors(false)) {
                setTip("正在识别…(10s)", R.color.color_ff8a53f7);
                startCountDown();
            } else {
                showErrorTip(4);
                verboseLog("## start detection failure");
            }
        }
    }

    CountDownTimer mCountDownTimer;

    private void startCountDown() {
//        Observable.interval(10,TimeUnit.SECONDS).doOnEach(new )
        mCountDownTimer = new CountDownTimer(10000, 1000) {
            @Override
            public void onTick(long millisUntilFinished) {
                int leftTime = (int) (millisUntilFinished / 1000);
                setTip("正在识别…(" + (leftTime + 1) + "s)", R.color.color_ff8a53f7);
            }

            @Override
            public void onFinish() {
                setTip("未识别到活动内容", R.color.color_ff7d7d7d);
                stopDetection();
                btnRegAgain.setVisibility(View.VISIBLE);
                ivWave.setImageResource(R.drawable.ic_sync_now_fail);
            }
        };
        mCountDownTimer.start();
    }

    private void setTip(String tip, int colorId) {
        tvTip.setText(tip);
        tvTip.setTextColor(getResources().getColor(colorId));
    }

    /**
     * Stops the capture audio thread and the detection SDK.
     **/
    private synchronized void stopDetection() {
        synchronized (this) {
            rlRoot.setEnabled(false);
            destroyCaptureAndDetectors();
        }
    }

    /**
     * Kills the audio capture thread and the detectors
     * <p>
     * This method will block until the worker thread is stopped.
     **/
    private synchronized void destroyCaptureAndDetectors() {
        if (null != mAudioCapture) {
            mAudioCapture.interrupt();
            if (mAudioCapture.isAlive()) {
                try {
                    mAudioCapture.join();
                } catch (Exception e) {
                    e.printStackTrace();
                    verboseLog(e.getMessage());
                }
            }
            // It's warning obligatory
            // The method isn't callback method of the Object class
            mAudioCapture.finalize();
            mAudioCapture = null;
        }

        // remove from the queue
        for (int i = mDetectors.size() - 1; i >= 0; i--) {
            mDetectors.elementAt(i).stop();
            mDetectors.removeElementAt(i);
        }
    }

    /**
     * SpringFestivalGalaActivity offices as a proxy from the AudioCapture to the AudioDetectors
     **/
    public boolean pushAudioBuffer(byte audioSampleBuffer[], int audioSampleBufferSize) {
        boolean pushed = true;

        for (int i = 0; i < mDetectors.size(); i++) {
            pushed = mDetectors.elementAt(i).pushAudioBuffer(audioSampleBuffer, audioSampleBufferSize);
            if (!pushed) {
                break;
            }
        }
        return pushed;
    }

    /**
     * Run time permissions request (since API 23)
     *
     * @param requestCode int used to handle pending action at onRequestPermissionsResult callback
     * @return true if permissions are already granted, false if not (in this case a requestPermissions procedure is launched using the requestCode provided)
     **/
    private synchronized boolean checkPermissions(int requestCode) {
        List<String> permissionsList = new ArrayList<>();

        if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED)
            permissionsList.add(Manifest.permission.RECORD_AUDIO);
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)
            permissionsList.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
        if (permissionsList.size() > 0) {
            ActivityCompat.requestPermissions(this, permissionsList.toArray(new String[permissionsList.size()]),
                    requestCode);
            return false;
        }
        return true;
    }

    /**
     * Handle RequestPermissionsResult callback
     **/
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        switch (requestCode) {
            case REQUEST_START_DETECTION_PERMISSIONS: {
                Map<String, Integer> perms = new HashMap<>();
                // Initial
                perms.put(Manifest.permission.RECORD_AUDIO, PackageManager.PERMISSION_GRANTED);
                perms.put(Manifest.permission.WRITE_EXTERNAL_STORAGE, PackageManager.PERMISSION_GRANTED);
                // Fill with results
                for (int i = 0; i < permissions.length; i++)
                    perms.put(permissions[i], grantResults[i]);
                // Check
                if (perms.get(Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED
                        && perms.get(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
                    // All Permissions Granted: launch pending action
                    if (requestCode == REQUEST_START_DETECTION_PERMISSIONS)
                        startDetection();
                } else {
                    Toast.makeText(getApplicationContext(), "请授予采集音频的权限。", Toast.LENGTH_LONG).show();
                }
            }
            break;
            default:
                super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }

    /**
     * Method for centralization log trace on Android
     * <p>
     * Static method
     *
     * @param message message log trace
     **/
    public static void verboseLog(String message) {
        Log.v(TAG, message);
    }
}
